package com.yt.user.server.api.cms;

import com.yt.common.constant.Result;
import com.yt.user.models.dto.AdminLoginDTO;
import com.yt.user.models.dto.SysAdminDTO;
import com.yt.user.models.service.IUserSysAdminRemoteService;
import com.yt.user.models.vo.AdminLoginVO;
import com.yt.common.utils.Md5Utils;
import com.yt.user.server.service.impl.SysAdminFallbackServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@RestController
@RequestMapping("/api/admin")
@Api(tags = "管理员登录接口")
public class AdminLoginController {
    
    private static final Logger log = LoggerFactory.getLogger(AdminLoginController.class);

    @DubboReference(check = false, timeout = 10000, retries = 0, interfaceClass = IUserSysAdminRemoteService.class, lazy = true)
    private IUserSysAdminRemoteService sysAdminRemoteService;
    
    @Autowired
    private SysAdminFallbackServiceImpl sysAdminFallbackService;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    // 登录失败次数限制阈值
    private static final int MAX_LOGIN_ATTEMPTS = 5;
    // 锁定时间（分钟）
    private static final int LOCK_TIME_MINUTES = 15;

    @PostMapping("/login")
    @ApiOperation("管理员登录")
    public Result<AdminLoginVO> login(@Valid @RequestBody AdminLoginDTO adminLoginDTO) {
        // 1. 参数校验
        if (adminLoginDTO.getUsername() == null || adminLoginDTO.getUsername().isEmpty() ||
            adminLoginDTO.getPassword() == null || adminLoginDTO.getPassword().isEmpty()) {
            return Result.fail("用户名或密码不能为空");
        }

        // 2. 检查是否被锁定
        String lockKey = "login_lock:" + adminLoginDTO.getUsername();
        if (Boolean.TRUE.equals(redisTemplate.hasKey(lockKey))) {
            return Result.fail("登录失败次数过多，请" + LOCK_TIME_MINUTES + "分钟后再试");
        }

        // 3. 验证码校验（如果启用）
        if (adminLoginDTO.getCaptchaCode() != null && !adminLoginDTO.getCaptchaCode().isEmpty()) {
            if (adminLoginDTO.getCaptchaKey() == null || adminLoginDTO.getCaptchaKey().isEmpty()) {
                return Result.fail("验证码标识不能为空");
            }
            
            String captchaKey = "captcha:" + adminLoginDTO.getCaptchaKey();
            String correctCaptcha = (String) redisTemplate.opsForValue().get(captchaKey);
            
            if (correctCaptcha == null) {
                return Result.fail("验证码已过期");
            }
            
            if (!correctCaptcha.equalsIgnoreCase(adminLoginDTO.getCaptchaCode())) {
                return Result.fail("验证码错误");
            }
            
            // 验证成功后删除验证码，防止重复使用
            redisTemplate.delete(captchaKey);
        }

        // 4. 查询管理员信息
        SysAdminDTO admin = null;
        try {
            if (sysAdminRemoteService == null) {
                log.error("sysAdminRemoteService is null, dubbo service not initialized properly. Please check if yt-sys-server is running and Zookeeper is available.");
                // 使用本地回退实现
                admin = sysAdminFallbackService.getByUsername(adminLoginDTO.getUsername());
                log.info("使用本地回退服务查询管理员信息");
            } else {
                admin = sysAdminRemoteService.getByUsername(adminLoginDTO.getUsername());
            }
        } catch (Exception e) {
            log.error("调用sysAdminRemoteService.getByUsername发生异常: ", e);
            // 出现异常时使用本地回退实现
            try {
                admin = sysAdminFallbackService.getByUsername(adminLoginDTO.getUsername());
                log.info("远程服务调用异常，使用本地回退服务查询管理员信息");
            } catch (Exception fallbackException) {
                log.error("本地回退服务调用也失败: ", fallbackException);
                return Result.fail("系统服务异常，请稍后再试");
            }
        }
        
        if (admin == null) {
            return Result.fail("用户名不存在");
        }

        // 5. 账号状态校验
        if (admin.getStatus() == 0) {
            return Result.fail("账号已被禁用，请联系超级管理员");
        }

        // 6. 密码校验
        String encryptedPassword = Md5Utils.MD5Encode(adminLoginDTO.getPassword());
        if (!encryptedPassword.equals(admin.getPassword())) {
            // 记录失败次数
            String failCountKey = "login_fail_count:" + adminLoginDTO.getUsername();
            redisTemplate.opsForValue().increment(failCountKey, 1);
            // 设置过期时间
            redisTemplate.expire(failCountKey, LOCK_TIME_MINUTES, TimeUnit.MINUTES);
            
            // 获取当前失败次数
            Object failCountObj = redisTemplate.opsForValue().get(failCountKey);
            int failCount = failCountObj != null ? ((Integer) failCountObj).intValue() : 0;
            
            // 达到最大失败次数，锁定账号
            if (failCount >= MAX_LOGIN_ATTEMPTS) {
                redisTemplate.opsForValue().set(lockKey, "locked", LOCK_TIME_MINUTES, TimeUnit.MINUTES);
                redisTemplate.delete(failCountKey);
                return Result.fail("登录失败次数过多，请" + LOCK_TIME_MINUTES + "分钟后再试");
            }
            
            return Result.fail("密码错误，还剩" + (MAX_LOGIN_ATTEMPTS - failCount) + "次机会");
        }

        // 7. 登录成功，清除失败次数记录
        String failCountKey = "login_fail_count:" + adminLoginDTO.getUsername();
        redisTemplate.delete(failCountKey);

        // 8. 登录成功处理
        // 生成身份凭证（使用简单的token方案）
        String token = UUID.randomUUID().toString().replace("-", "");
        Long expireTime = System.currentTimeMillis() + 2 * 60 * 60 * 1000; // 2小时过期
        
        // 将token存入Redis
        String tokenKey = "admin_token:" + token;
        redisTemplate.opsForValue().set(tokenKey, admin.getAdminId(), 2, TimeUnit.HOURS); // 2小时过期

        // 9. 构造返回结果
        AdminLoginVO adminLoginVO = new AdminLoginVO();
        adminLoginVO.setToken(token);
        adminLoginVO.setExpireTime(expireTime);
        
        AdminLoginVO.AdminInfo adminInfo = new AdminLoginVO.AdminInfo();
        adminInfo.setId(admin.getAdminId());
        adminInfo.setUsername(admin.getUsername());
        adminInfo.setRole("超级管理员"); // 实际应从数据库获取角色信息
        
        adminLoginVO.setAdminInfo(adminInfo);
        
        return Result.success(adminLoginVO);
    }
}